Using Django on Smeserver 7.5

Introduction

Creating web-based information systems with Django is fun. For deployment of the productive system I wanted to use an Smeserver 7.5. SME7 is based on CentOS 4.X, which comes with Python 2.3.4. This restricts you to Django 1.1 together with Python 2.3, which are — to put it mildly — outdated. At the time of this writing Django 1.4 with Python 2.7 is a charme. Thus, I figured out how to put Django 1.4 at Python 2.7 onto an SME 7.5. Please let me know if you spot any errors or omissions. Here we go…

Problem Statement

We assume a working installation of Smeserver 7.5 as myserver. Further, we assume a working django project using Python 2.7 on any development host. We declare the metasyntactic variable myDjangoProject as the django project’s name. We declare the metasyntactic variable xyz as myserver’s path (i.e., http(s)://myserver/xyz) where the django project should be provided. The server should host and provide the django project.

The Method

First, we create an isolated environment for our installation. Go to the server admin page and create an user django. For security reasons we won’t give the django user any super user rights. Therefore, login as user django on one terminal and login as user root on another terminal. Assume user django’s context first throughout the instructions if not stated otherwise.
Inside user root’s context install required development packages. We will remove them when we are done, because they are an attack vector.
yum install gcc
Inside user django’s context we install Python 2.7 following the instructions from http://h1nf.anu.edu.au/collaborate/pyfusion/documentation/install/centos/centos4.8.html.
export PYTHONPATH=$PYTHONPATH:$HOME/code/python
mkdir -p code/python
export SOURCEDIR=$HOME/source
mkdir $SOURCEDIR
export LOCALDIR=$HOME/local
mkdir $LOCALDIR
export PATH=$LOCALDIR/bin:$PATH
touch .bashrc 
ln .bashrc .bash_profile
nano .bashrc
In the .bashrc file append the following lines:export PYTHONPATH=$PYTHONPATH:$HOME/code/python
export LOCALDIR=$HOME/local
export PATH=$LOCALDIR/bin:$PATH
Exit from nano with Ctrl+X and say “Yes, I want to save the .bashrc file.” Then proceed in user django’s shell:
cd $SOURCEDIR
wget http://www.python.org/ftp/python/2.7.3/Python-2.7.3.tar.bz2
tar -xjf Python-2.7.3.tar.bz2
cd Python-2.7.3
./configure --prefix=$LOCALDIR
make
make install
Test your Python! It should look something like this:
-bash-3.00$ python
Python 2.7.3 (default, Apr 12 2012, 18:57:10)
[GCC 3.4.6 20060404 (Red Hat 3.4.6-11)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 
We want to use PIP in user django’s context.
cd $SOURCEDIR
wget http://pypi.python.org/packages/2.7/s/setuptools/setuptools-0.6c11-py2.7.egg
sh setuptools-0.6c11-py2.7.egg --prefix=$LOCALDIR
easy_install PIP
PIP gives us the latest Django. If you need a specific version refer to PIP's documentation.
pip install django
It’s time to setup the django site. If you want to build one from scratch refer to Django's great tutorial. I take mine from my development repository. No matter how, put your django project into user django’s code directory (i.e., ~/code/python), which we refer to in the pythonpath environment variable.
cd ~/code/python
svn co https://mySvnServer.tld/myRepository/myDjangoProject myDjangoProject
For the fun of it, let’s peek test our django installation.
cd myDjangoProject
python manage.py syncdb
python manage.py runserver
I guess it complains about missing packages. Use PIP to fix this. Because additional packages are quiet individual I think you should go on your own here. I collected some experiences down in the section called Optional Packages↓. Repeat the test until the test server succeeds. Then, we stop the test server and set it up for productive service with fastcgi following the instructions from http://wiki.contribs.org/Mod_FastCGI inside user root’s context.
cd ~
wget http://mirror.contribs.org/smeserver/contribs/nhall/sme7/contribs/mod_fastcgi/rpms/mod_fastcgi-2.4.6-1.i386.rpm
wget http://mirror.contribs.org/smeserver/contribs/nhall/sme7/contribs/mod_fastcgi/rpms/smeserver-mod_fastcgi-0.1-1.noarch.rpm
yum localinstall smeserver-mod_fastcgi-0.1-1.noarch.rpm mod_fastcgi-2.4.6-1.i386.rpm
Django’s fast_cgi server requires the python flup package.
pip install flup
Now we have to link the http daemon with our django installation. Therefore, we start a test fcgi server inside user django’s context following instructions from https://docs.djangoproject.com/en/dev/howto/deployment/fastcgi/.
python manage.py runfcgi daemonize=false method=threaded host=127.0.0.1 port=3533
We adapt their instructions how to configure the Apache to smeserver’s configuration template system. Configure Django’s fcgi server as Apache’s external fcgi server.
mkdir -p /etc/e-smith/templates-custom/etc/httpd/conf/httpd.conf
nano /etc/e-smith/templates-custom/etc/httpd/conf/httpd.conf/80FastCgiExternalServer
FastCgiExternalServer external_django_fastcgi_server -host 127.0.0.1:3533
Then we configure, how Apache should route requests to the fcgi server. For this, we assume that you want to publish your django project at http(s)://yourserver/xyz root url.
mkdir /etc/e-smith/templates-custom/etc/httpd/conf/httpd.conf/VirtualHosts
nano /etc/e-smith/templates-custom/etc/httpd/conf/httpd.conf/VirtualHosts/69django
	Alias /xyz external_django_fastcgi_server
	<Location /xyz >
		SetHandler fastcgi-script
		Options +ExecCGI
		allow from all
	</Location>
Then we apply the two new templates through:
expand-template /etc/httpd/conf/httpd.conf
sv t httpd-e-smith
Now, your django project should be accessible under http(s)://yourserver/xyz. The last issue is, that we manually started the fcgi server. First, stop the manually started server (Ctrl+C). Then as user django create an executable runserver script.
touch ~/runserver
chmod u+x ~/runserver
nano ~/runserver
#!/bin/sh
cd ~/code/python/myDjangoProject
python manage.py runfcgi daemonize=false method=threaded host=127.0.0.1 port=3533
Then, we link the runserver script into smeserver’s startup framework.
db configuration set django service status enabled
ln -s /etc/rc.d/init.d/e-smith-service /etc/rc.d/rc7.d/S85django
ln -s /etc/rc.d/init.d/daemontools  /etc/rc.d/init.d/django
mkdir /var/service/django
ln -s /var/service/django /service/django
touch /var/service/django/run
chmod u+x /var/service/django/run
nano /var/service/django/run
#!/bin/sh
su -l --command=~/runserver django
Now, your django project should be available 24/7. That’s it.

Polishing for Security

Remove all development packages! They are an attack vector.
yum remove gcc cpp *-devel *headers
Set as much files as possible to read-only. Finally, your sqlite database file should be the only writable file inside django’s home when going online.
Disable any remote access to user django. Use http://wiki.contribs.org/Remoteuseraccess, reset the password, and double-verify.

Optional Packages

south

Never again without south! I developed with south 0.7.3. When I deployed, pip retrieved south 0.7.4, which produced syntax errors at SQL. I pinned south to version 0.7.3 and it was fixed.
pip install south==0.7.3

django-simple-captcha

I use django-simple-captcha. This is not trivial, because it uses _imagingft through the PIL, which doesn’t install properly out-of-the-box. Here’s how I did it.
yum install gcc freetype-devel
pip install PIL
yum remove gcc freetype-devel
pip install django-simple-captcha

smtplib.SMTP_SSL

As you have Django running on your smeserver you want to send emails with the very same server, of course. This requires an ssl-enabled smtp client. If python complains about a missing SMTP_SSL class then the _ssl module is missing. You need to have the openssl-devel package yum-installed during the python build to fix this. If you forgot it at first just rebuild python with an available openssl-devel package following the configure-make-makeinstall-instructions stated at the top of the section called The Method↑. Please don’t forget to remove any devel packages afterwards!

pysqlite

If you configured the sqlite backend, django complains about missing pysqlite package out-of-the-box. Here’s how I did it.
yum install gcc sqlite-devel
pip install pysqlite
yum remove gcc sqlite-devel